import struct
import threading
import public.Public_data as PD
import time
from datetime import datetime, timezone, timedelta
import public.UDP_connect as udp

# _heartbeat = PD.Heartbeat_Data()
# _enable = PD.Enable_Data()
# _timestamp = PD.Timestamp_Data()
_heartbeat_dict = {}

def parse_udp_packet(addr,data,IOC_opr):
    if data[:2] == b'\x48\x42' or data[:4] == b"\x4d\x41\x53\x54":
        if addr in _heartbeat_dict.keys():
             _heartbeat_dict[addr] += 1
        else:
             _heartbeat_dict[addr] = 1
        return_data = parse_heartbeat_packet(data)
        
        for pvname,host in IOC_opr.host_dict.items():
            if addr == host:
                IOC_opr.setParam(reason=pvname+":HeartBeat_Ready",value=int(return_data["ready_signal"]))
                print(f"ip:{addr},data:{return_data}")
#         _heartbeat.Device_IP = addr
#         _heartbeat.Ready_Signal = 1
#         #print(parse_heartbeat_packet(data), 'heartbeat')
#         #print(type(_heartbeat.Device_No))

    # elif data[:2] == b'\x45\x4e':
    #     value = parse_enable_control_packet(data)["Enable Status"]
    #     if value == 1:
    #         for pvname in IOC_opr.host_dict.keys():
    #             IOC_opr.setParam(reason=pvname+":InterLock",value=1)
    #             # print("恢复")
    #     IOC_opr.setParam(reason="TIMS:WR:Enable_Bos",value=int(value))
        
    elif data[:2] == b'\x54\x4d':
        
        result_data = parse_lock_loss_timestamp_packet(data)
        s = result_data["s"]
        ns = result_data["ns"]
        _UTC = result_data["UTC"]
        print(f"ip:{addr},s:{s},ns:{ns},UTC:{_UTC}")
        try:
            index = list(IOC_opr.host_dict.values()).index(addr)
            pvname = list(IOC_opr.host_dict.keys())[index]
            #IOC_opr.setParam(reason="TIMS:WR:Timestamp_s",value=s)
            #IOC_opr.setParam(reason="TIMS:WR:Timestamp_ns",value=ns)
            IOC_opr.setParam(reason=pvname+":InterlockTimestamp_UTC",value=_UTC)
            # IOC_opr.setParam(reason=pvname+":InterLock",value=0)
            # IOC_opr.setParam(reason=pvname+":InterLock_L",value=0)
            IOC_opr.setParam(reason="TIMS:WR:Enable_Bos",value=0)
            
        except:
            print(f"{addr} is not fond")
def parse_heartbeat_packet(data):
    if len(data) != 18:
        print(f"Invalid heartbeat packet length: {len(data)}")
        return None
    identifier, wr_device_no, device_group, ready_signal, reserved, crc = struct.unpack('!2s I B B 8s H', data)
    return {
        'WR Device No': wr_device_no,
        'Device Group': device_group,
        'ready_signal':ready_signal
        #'Ready Signal': int((ready_signal & (1 << 4)) / (1 << 4)),
    }

# def parse_interlock_packet(data):
#     if len(data) != 18:
#         print(f"Invalid interlock packet length: {len(data)}")
#         return None
#     identifier, wr_device_no, interlock_status, reserved, crc = struct.unpack('!2s I H 8s H', data)
#     print(identifier, wr_device_no, interlock_status, reserved, crc)
#     return interlock_status

def parse_enable_control_packet(data):
    if len(data) != 18:
        print(f"Invalid enable control packet length: {len(data)}")
        return None
    identifier, master_device_no, enable_status, reserved, crc = struct.unpack('!2s 4s H 8s H', data)
    enable_status = enable_status & 0x01  # 只取最低位
    print({
        'Master Device No': master_device_no.decode('ascii'),
        'Enable Status': enable_status,
    })
    return {
        'Master Device No': master_device_no.decode('ascii'),
        'Enable Status': enable_status,
    }
def Timestamp_Trans(timestamp):
    timestamp_data = timestamp
    ns_timestamp = (int(timestamp_data[0:3].hex(),16) << 4)+(timestamp_data[3] >> 4) 
    s_timestamp = ((timestamp_data[3] & 15) << 36) +(int(timestamp_data[4:8].hex(),16) << 4) + (timestamp_data[-1] >> 4)
    # 将秒计数和纳秒计数转换为UTC时间
    utc_time = datetime.fromtimestamp(s_timestamp, tz=timezone.utc) + timedelta(microseconds=ns_timestamp *16 / 1000)
    # 格式化为字符串
    utc_time_str = utc_time.isoformat()
    return {"s":s_timestamp,"ns":ns_timestamp,"UTC": utc_time_str}

def parse_lock_loss_timestamp_packet(data):
    if len(data) != 18:
        print(f"Invalid lock loss timestamp packet length: {len(data)}")
        return None
    identifier, device_no, timestamp, reserved, crc = struct.unpack('!2s I 9s s H', data)
    return Timestamp_Trans(timestamp)


def bos_threading_multi(IOC_opr):
    sockmulti=udp.join_multicast_group()
    while True:
            time.sleep(0.01)
            data, addr = sockmulti.recvfrom(1024)
            # print(f"Received data multi from {addr}: {data.hex()}")
            parse_udp_packet(addr[0],data,IOC_opr)

def bos_threading_unicast(IOC_opr):
    sockuni=udp.listen_unicast()
    while True:
            time.sleep(0.01)
            data, addr = sockuni.recvfrom(1024)
            # print(f"Received data unicast from {addr}: {data.hex()}")
            parse_udp_packet(addr[0],data,IOC_opr)


def check_state_threading(IOC_opr):
    IOC_opr.setParam("TIMS:WR:Check_State",1)
    while True:
        all_heartbeat = 1
        IOC_opr.setParam(reason="TIMS:WR:Wait_State",value=IOC_opr.SNMP.waitover())
        for pvname,host in IOC_opr.host_dict.items():
            if not host == "10.10.14.30":
                _heartbeat_dict[host] = 0
        time.sleep(2)
        for pvname,host in IOC_opr.host_dict.items():
            if host in _heartbeat_dict.keys():
                if _heartbeat_dict[host] >= 1:
                    IOC_opr.setParam(reason=pvname+":HeartBeat",value=1)
                else:
                    IOC_opr.setParam(reason=pvname+":HeartBeat",value=0)
                    all_heartbeat = 0
            else:
                IOC_opr.setParam(reason=pvname+":HeartBeat",value=0)
        
        IOC_opr.setParam(reason="TIMS:WR:HeartBeat_Enable_Bos",value=all_heartbeat)
                 
def bos(IOC_opr):
    # 启动多播监听线程
    multicast_thread = threading.Thread(target=bos_threading_multi,args=(IOC_opr,))
    multicast_thread.start()
    # 启动单播监听线程
    unicast_thread = threading.Thread(target=bos_threading_unicast,args=(IOC_opr,))
    unicast_thread.start()
    # 启动检查线程，检查心跳，失锁状态
    check_thread = threading.Thread(target=check_state_threading,args=(IOC_opr,))
    check_thread.start()


# # IOC修改主程序
#     def handle_read(self):
        
#         Device_No = udp_parse._heartbeat.Device_No
#         Ready_Signal = udp_parse._heartbeat.Ready_Signal
        
#         if not (Device_No == None or Ready_Signal == None):
#             try:
#                 index = list(self.host_dict.values()).index(Device_No)
#                 pvname = list(self.host_dict.keys())[index]
#                 self.setParam(reason=pvname+":HeartBeat",value=Ready_Signal)
                
#             except:
#                 # print(Device_No,ip)
#                 pass
        
#         Enable_Status = udp_parse._enable.Enable_Status
#         if not (Device_No == None or  Enable_Status == None):
#             # cached_status = self.enable_cache.get(BOS_F)
#             # if cached_status != Enable_Status:
#             self.enable_cache["TIMS:WR:Enable_Bos"] = Enable_Status
#             self.setParam(reason="TIMS:WR:Enable_Bos", value=Enable_Status)
#             # print(BOS_F + ":EnableControl:",Enable_Status)
#             if Enable_Status == 1:
#                 for pvname in self.name_dict.keys():
#                     self.setParam(reason=pvname + ":InterLock", value=1)
#             else:
#                 for pvname in self.name_dict.keys():
#                     if not self.bypass_states[pvname]:
#                         self.setParam(reason=pvname + ":InterLock", value=0)

        
#         Device_No = udp_parse._timestamp.Device_No
#         Timestamp = udp_parse._timestamp.Timestamp
#         if Device_No is not None and Timestamp is not None:
#             try:
#                 index = list(self.host_dict.values()).index(Device_No)
#                 pvname = list(self.host_dict.keys())[index]
#             except:
#                 # print(Device_No,ip)
#                 pass
#             current_timestamp = self.timestamp_cache.get(pvname)
#             if current_timestamp != Timestamp:
#                 self.timestamp_cache[pvname] = Timestamp
#                 self.setParam(reason=f"{pvname}:Timestamp_ns", value=Timestamp["ns"])
#                 self.setParam(reason=f"{pvname}:Timestamp_s", value=Timestamp["s"])
#                 self.setParam(reason=f"{pvname}:Timestamp_UTC", value=Timestamp["UTC"])
#                 if not self.bypass_states.get(pvname, False) and Enable_Status == 0:
#                     self.setParam(reason=f"{pvname}:InterLock",value=0)
#             # self.setParam(reason=pvname + ":InterLock", value=0)
#             # print(pvname+":Timestamp_s:",Timestamp["s"],pvname+":Timestamp_ns:",Timestamp["ns"],pvname + ":Timestamp_UTC:",Timestamp["UTC"])
#             # if not self.bypass_states.get(pvname, False):
#             #     self.setParam(reason=pvname + ":InterLock", value=0)
#                 # print("interlock:",pvname+":InterLock")
    
